home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / dpmigcc5.zip / RSX / SOURCE / FPU-EMU / REG_ROUN.S < prev    next >
Text File  |  1994-05-27  |  18KB  |  702 lines

  1.     .file "reg_round.S"
  2. /*---------------------------------------------------------------------------+
  3.  |  reg_round.S                                                              |
  4.  |                                                                           |
  5.  | Rounding/truncation/etc for FPU basic arithmetic functions.               |
  6.  |                                                                           |
  7.  | Copyright (C) 1993                                                        |
  8.  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
  9.  |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  10.  |                                                                           |
  11.  | This code has four possible entry points.                                 |
  12.  | The following must be entered by a jmp intruction:                        |
  13.  |   fpu_reg_round, fpu_reg_round_sqrt, and fpu_Arith_exit.                  |
  14.  |                                                                           |
  15.  | The _round_reg entry point is intended to be used by C code.              |
  16.  | From C, call as:                                                          |
  17.  | void round_reg(FPU_REG *arg, unsigned int extent, unsigned int control_w) |
  18.  |                                                                           |
  19.  | For correct "up" and "down" rounding, the argument must have the correct  |
  20.  | sign.                                                                     |
  21.  |                                                                           |
  22.  +---------------------------------------------------------------------------*/
  23.  
  24. /*---------------------------------------------------------------------------+
  25.  | Four entry points.                                                        |
  26.  |                                                                           |
  27.  | Needed by both the fpu_reg_round and fpu_reg_round_sqrt entry points:     |
  28.  |  %eax:%ebx  64 bit significand                                            |
  29.  |  %edx       32 bit extension of the significand                           |
  30.  |  %edi       pointer to an FPU_REG for the result to be stored             |
  31.  |  stack      calling function must have set up a C stack frame and         |
  32.  |             pushed %esi, %edi, and %ebx                                   |
  33.  |                                                                           |
  34.  | Needed just for the fpu_reg_round_sqrt entry point:                       |
  35.  |  %cx  A control word in the same format as the FPU control word.          |
  36.  | Otherwise, PARAM4 must give such a value.                                 |
  37.  |                                                                           |
  38.  |                                                                           |
  39.  | The significand and its extension are assumed to be exact in the          |
  40.  | following sense:                                                          |
  41.  |   If the significand by itself is the exact result then the significand   |
  42.  |   extension (%edx) must contain 0, otherwise the significand extension    |
  43.  |   must be non-zero.                                                       |
  44.  |   If the significand extension is non-zero then the significand is        |
  45.  |   smaller than the magnitude of the correct exact result by an amount     |
  46.  |   greater than zero and less than one ls bit of the significand.          |
  47.  |   The significand extension is only required to have three possible       |
  48.  |   non-zero values:                                                        |
  49.  |       less than 0x80000000  <=> the significand is less than 1/2 an ls    |
  50.  |                                 bit smaller than the magnitude of the     |
  51.  |                                 true exact result.                        |
  52.  |         exactly 0x80000000  <=> the significand is exactly 1/2 an ls bit  |
  53.  |                                 smaller than the magnitude of the true    |
  54.  |                                 exact result.                             |
  55.  |    greater than 0x80000000  <=> the significand is more than 1/2 an ls    |
  56.  |                                 bit smaller than the magnitude of the     |
  57.  |                                 true exact result.                        |
  58.  |                                                                           |
  59.  +---------------------------------------------------------------------------*/
  60.  
  61. /*---------------------------------------------------------------------------+
  62.  |  The code in this module has become quite complex, but it should handle   |
  63.  |  all of the FPU flags which are set at this stage of the basic arithmetic |
  64.  |  computations.                                                            |
  65.  |  There are a few rare cases where the results are not set identically to  |
  66.  |  a real FPU. These require a bit more thought because at this stage the   |
  67.  |  results of the code here appear to be more consistent...                 |
  68.  |  This may be changed in a future version.                                 |
  69.  +---------------------------------------------------------------------------*/
  70.  
  71.  
  72. #include "fpu_asm.h"
  73. #include "exception.h"
  74. #include "control_w.h"
  75.  
  76. /* Flags for FPU_bits_lost */
  77. #define    LOST_DOWN    $1
  78. #define    LOST_UP        $2
  79.  
  80. /* Flags for FPU_denormal */
  81. #define    DENORMAL    $1
  82. #define    UNMASKED_UNDERFLOW $2
  83.  
  84.  
  85. #ifdef REENTRANT_FPU
  86. /*    Make the code re-entrant by putting
  87.     local storage on the stack: */
  88. #define FPU_bits_lost    (%esp)
  89. #define FPU_denormal    1(%esp)
  90.  
  91. #else
  92. /*    Not re-entrant, so we can gain speed by putting
  93.     local storage in a static area: */
  94. .data
  95.     .align 2,0
  96. FPU_bits_lost:
  97.     .byte    0
  98. FPU_denormal:
  99.     .byte    0
  100. #endif REENTRANT_FPU
  101.  
  102.  
  103. .text
  104.     .align 2,144
  105. .globl fpu_reg_round
  106. .globl fpu_reg_round_sqrt
  107. .globl fpu_Arith_exit
  108. .globl _round_reg
  109.  
  110. /* Entry point when called from C */
  111. _round_reg:
  112.     pushl    %ebp
  113.     movl    %esp,%ebp
  114.     pushl    %esi
  115.     pushl    %edi
  116.     pushl    %ebx
  117.  
  118.     movl    PARAM1,%edi
  119.     movl    SIGH(%edi),%eax
  120.     movl    SIGL(%edi),%ebx
  121.     movl    PARAM2,%edx
  122.     movl    PARAM3,%ecx
  123.     jmp    fpu_reg_round_sqrt
  124.  
  125. fpu_reg_round:            /* Normal entry point */
  126.     movl    PARAM4,%ecx
  127.  
  128. fpu_reg_round_sqrt:        /* Entry point from wm_sqrt.S */
  129.  
  130. #ifdef REENTRANT_FPU
  131.     pushl    %ebx        /* adjust the stack pointer */
  132. #endif REENTRANT_FPU
  133.  
  134. #ifdef PARANOID
  135. /* Cannot use this here yet */
  136. /*    orl    %eax,%eax */
  137. /*    jns    L_entry_bugged */
  138. #endif PARANOID
  139.  
  140.     cmpl    EXP_UNDER,EXP(%edi)
  141.     jle    xMake_denorm            /* The number is a de-normal */
  142.  
  143.     movb    $0,FPU_denormal            /* 0 -> not a de-normal */
  144.  
  145. xDenorm_done:
  146.     movb    $0,FPU_bits_lost        /* No bits yet lost in rounding */
  147.  
  148.     movl    %ecx,%esi
  149.     andl    CW_PC,%ecx
  150.     cmpl    PR_64_BITS,%ecx
  151.     je    LRound_To_64
  152.  
  153.     cmpl    PR_53_BITS,%ecx
  154.     je    LRound_To_53
  155.  
  156.     cmpl    PR_24_BITS,%ecx
  157.     je    LRound_To_24
  158.  
  159. #ifdef PECULIAR_486
  160. /* With the precision control bits set to 01 "(reserved)", a real 80486
  161.    behaves as if the precision control bits were set to 11 "64 bits" */
  162.     cmpl    PR_RESERVED_BITS,%ecx
  163.     je    LRound_To_64
  164. #ifdef PARANOID
  165.     jmp    L_bugged_denorm_486
  166. #endif PARANOID
  167. #else
  168. #ifdef PARANOID
  169.     jmp    L_bugged_denorm    /* There is no bug, just a bad control word */
  170. #endif PARANOID
  171. #endif PECULIAR_486
  172.  
  173.  
  174. /* Round etc to 24 bit precision */
  175. LRound_To_24:
  176.     movl    %esi,%ecx
  177.     andl    CW_RC,%ecx
  178.     cmpl    RC_RND,%ecx
  179.     je    LRound_nearest_24
  180.  
  181.     cmpl    RC_CHOP,%ecx
  182.     je    LCheck_truncate_24
  183.  
  184.     cmpl    RC_UP,%ecx        /* Towards +infinity */
  185.     je    LUp_24
  186.  
  187.     cmpl    RC_DOWN,%ecx        /* Towards -infinity */
  188.     je    LDown_24
  189.  
  190. #ifdef PARANOID
  191.     jmp    L_bugged_round24
  192. #endif PARANOID
  193.  
  194. LUp_24:
  195.     cmpb    SIGN_POS,SIGN(%edi)
  196.     jne    LCheck_truncate_24    /* If negative then  up==truncate */
  197.  
  198.     jmp    LCheck_24_round_up
  199.  
  200. LDown_24:
  201.     cmpb    SIGN_POS,SIGN(%edi)
  202.     je    LCheck_truncate_24    /* If positive then  down==truncate */
  203.  
  204. LCheck_24_round_up:
  205.     movl    %eax,%ecx
  206.     andl    $0x000000ff,%ecx
  207.     orl    %ebx,%ecx
  208.     orl    %edx,%ecx
  209.     jnz    LDo_24_round_up
  210.     jmp    LRe_normalise
  211.  
  212. LRound_nearest_24:
  213.     /* Do rounding of the 24th bit if needed (nearest or even) */
  214.     movl    %eax,%ecx
  215.     andl    $0x000000ff,%ecx
  216.     cmpl    $0x00000080,%ecx
  217.     jc    LCheck_truncate_24    /* less than half, no increment needed */
  218.  
  219.     jne    LGreater_Half_24    /* greater than half, increment needed */
  220.  
  221.     /* Possibly half, we need to check the ls bits */
  222.     orl    %ebx,%ebx
  223.     jnz    LGreater_Half_24    /* greater than half, increment needed */
  224.  
  225.     orl    %edx,%edx
  226.     jnz    LGreater_Half_24    /* greater than half, increment needed */
  227.  
  228.     /* Exactly half, increment only if 24th bit is 1 (round to even) */
  229.     testl    $0x00000100,%eax
  230.     jz    LDo_truncate_24
  231.  
  232. LGreater_Half_24:            /* Rounding: increment at the 24th bit */
  233. LDo_24_round_up:
  234.     andl    $0xffffff00,%eax    /* Truncate to 24 bits */
  235.     xorl    %ebx,%ebx
  236.     movb    LOST_UP,FPU_bits_lost
  237.     addl    $0x00000100,%eax
  238.     jmp    LCheck_Round_Overflow
  239.  
  240. LCheck_truncate_24:
  241.     movl    %eax,%ecx
  242.     andl    $0x000000ff,%ecx
  243.     orl    %ebx,%ecx
  244.     orl    %edx,%ecx
  245.     jz    LRe_normalise        /* No truncation needed */
  246.  
  247. LDo_truncate_24:
  248.     andl    $0xffffff00,%eax    /* Truncate to 24 bits */
  249.     xorl    %ebx,%ebx
  250.     movb    LOST_DOWN,FPU_bits_lost
  251.     jmp    LRe_normalise
  252.  
  253.  
  254. /* Round etc to 53 bit precision */
  255. LRound_To_53:
  256.     movl    %esi,%ecx
  257.     andl    CW_RC,%ecx
  258.     cmpl    RC_RND,%ecx
  259.     je    LRound_nearest_53
  260.  
  261.     cmpl    RC_CHOP,%ecx
  262.     je    LCheck_truncate_53
  263.  
  264.     cmpl    RC_UP,%ecx        /* Towards +infinity */
  265.     je    LUp_53
  266.  
  267.     cmpl    RC_DOWN,%ecx        /* Towards -infinity */
  268.     je    LDown_53
  269.  
  270. #ifdef PARANOID
  271.     jmp    L_bugged_round53
  272. #endif PARANOID
  273.  
  274. LUp_53:
  275.     cmpb    SIGN_POS,SIGN(%edi)
  276.     jne    LCheck_truncate_53    /* If negative then  up==truncate */
  277.  
  278.     jmp    LCheck_53_round_up
  279.  
  280. LDown_53:
  281.     cmpb    SIGN_POS,SIGN(%edi)
  282.     je    LCheck_truncate_53    /* If positive then  down==truncate */
  283.  
  284. LCheck_53_round_up:
  285.     movl    %ebx,%ecx
  286.     andl    $0x000007ff,%ecx
  287.     orl    %edx,%ecx
  288.     jnz    LDo_53_round_up
  289.     jmp    LRe_normalise
  290.  
  291. LRound_nearest_53:
  292.     /* Do rounding of the 53rd bit if needed (nearest or even) */
  293.     movl    %ebx,%ecx
  294.     andl    $0x000007ff,%ecx
  295.     cmpl    $0x00000400,%ecx
  296.     jc    LCheck_truncate_53    /* less than half, no increment needed */
  297.  
  298.     jnz    LGreater_Half_53    /* greater than half, increment needed */
  299.  
  300.     /* Possibly half, we need to check the ls bits */
  301.     orl    %edx,%edx
  302.     jnz    LGreater_Half_53    /* greater than half, increment needed */
  303.  
  304.     /* Exactly half, increment only if 53rd bit is 1 (round to even) */
  305.     testl    $0x00000800,%ebx
  306.     jz    LTruncate_53
  307.  
  308. LGreater_Half_53:            /* Rounding: increment at the 53rd bit */
  309. LDo_53_round_up:
  310.     movb    LOST_UP,FPU_bits_lost
  311.     andl    $0xfffff800,%ebx    /* Truncate to 53 bits */
  312.     addl    $0x00000800,%ebx
  313.     adcl    $0,%eax
  314.     jmp    LCheck_Round_Overflow
  315.  
  316. LCheck_truncate_53:
  317.     movl    %ebx,%ecx
  318.     andl    $0x000007ff,%ecx
  319.     orl    %edx,%ecx
  320.     jz    LRe_normalise
  321.  
  322. LTruncate_53:
  323.     movb    LOST_DOWN,FPU_bits_lost
  324.     andl    $0xfffff800,%ebx    /* Truncate to 53 bits */
  325.     jmp    LRe_normalise
  326.  
  327.  
  328. /* Round etc to 64 bit precision */
  329. LRound_To_64:
  330.     movl    %esi,%ecx
  331.     andl    CW_RC,%ecx
  332.     cmpl    RC_RND,%ecx
  333.     je    LRound_nearest_64
  334.  
  335.     cmpl    RC_CHOP,%ecx
  336.     je    LCheck_truncate_64
  337.  
  338.     cmpl    RC_UP,%ecx        /* Towards +infinity */
  339.     je    LUp_64
  340.  
  341.     cmpl    RC_DOWN,%ecx        /* Towards -infinity */
  342.     je    LDown_64
  343.  
  344. #ifdef PARANOID
  345.     jmp    L_bugged_round64
  346. #endif PARANOID
  347.  
  348. LUp_64:
  349.     cmpb    SIGN_POS,SIGN(%edi)
  350.     jne    LCheck_truncate_64    /* If negative then  up==truncate */
  351.  
  352.     orl    %edx,%edx
  353.     jnz    LDo_64_round_up
  354.     jmp    LRe_normalise
  355.  
  356. LDown_64:
  357.     cmpb    SIGN_POS,SIGN(%edi)
  358.     je    LCheck_truncate_64    /* If positive then  down==truncate */
  359.  
  360.     orl    %edx,%edx
  361.     jnz    LDo_64_round_up
  362.     jmp    LRe_normalise
  363.  
  364. LRound_nearest_64:
  365.     cmpl    $0x80000000,%edx
  366.     jc    LCheck_truncate_64
  367.  
  368.     jne    LDo_64_round_up
  369.  
  370.     /* Now test for round-to-even */
  371.     testb    $1,%ebx
  372.     jz    LCheck_truncate_64
  373.  
  374. LDo_64_round_up:
  375.     movb    LOST_UP,FPU_bits_lost
  376.     addl    $1,%ebx
  377.     adcl    $0,%eax
  378.  
  379. LCheck_Round_Overflow:
  380.     jnc    LRe_normalise
  381.  
  382.     /* Overflow, adjust the result (significand to 1.0) */
  383.     rcrl    $1,%eax
  384.     rcrl    $1,%ebx
  385.     incl    EXP(%edi)
  386.     jmp    LRe_normalise
  387.  
  388. LCheck_truncate_64:
  389.     orl    %edx,%edx
  390.     jz    LRe_normalise
  391.  
  392. LTruncate_64:
  393.     movb    LOST_DOWN,FPU_bits_lost
  394.  
  395. LRe_normalise:
  396.     testb    $0xff,FPU_denormal
  397.     jnz    xNormalise_result
  398.  
  399. xL_Normalised:
  400.     cmpb    LOST_UP,FPU_bits_lost
  401.     je    xL_precision_lost_up
  402.  
  403.     cmpb    LOST_DOWN,FPU_bits_lost
  404.     je    xL_precision_lost_down
  405.  
  406. xL_no_precision_loss:
  407.     /* store the result */
  408.     movb    TW_Valid,TAG(%edi)
  409.  
  410. xL_Store_significand:
  411.     movl    %eax,SIGH(%edi)
  412.     movl    %ebx,SIGL(%edi)
  413.  
  414.     xorl    %eax,%eax    /* No errors detected. */
  415.  
  416.     cmpl    EXP_OVER,EXP(%edi)
  417.     jge    L_overflow
  418.  
  419. fpu_reg_round_exit:
  420. #ifdef REENTRANT_FPU
  421.     popl    %ebx        /* adjust the stack pointer */
  422. #endif REENTRANT_FPU
  423.  
  424. fpu_Arith_exit:
  425.     popl    %ebx
  426.     popl    %edi
  427.     popl    %esi
  428.     leave
  429.     ret
  430.  
  431.  
  432. /*
  433.  * Set the FPU status flags to represent precision loss due to
  434.  * round-up.
  435.  */
  436. xL_precision_lost_up:
  437.     push    %eax
  438.     call    _set_precision_flag_up
  439.     popl    %eax
  440.     jmp    xL_no_precision_loss
  441.  
  442. /*
  443.  * Set the FPU status flags to represent precision loss due to
  444.  * truncation.
  445.  */
  446. xL_precision_lost_down:
  447.     push    %eax
  448.     call    _set_precision_flag_down
  449.     popl    %eax
  450.     jmp    xL_no_precision_loss
  451.  
  452.  
  453. /*
  454.  * The number is a denormal (which might get rounded up to a normal)
  455.  * Shift the number right the required number of bits, which will
  456.  * have to be undone later...
  457.  */
  458. xMake_denorm:
  459.     /* The action to be taken depends upon whether the underflow
  460.        exception is masked */
  461.     testb    CW_Underflow,%cl        /* Underflow mask. */
  462.     jz    xUnmasked_underflow        /* Do not make a denormal. */
  463.  
  464.     movb    DENORMAL,FPU_denormal
  465.  
  466.     pushl    %ecx        /* Save */
  467.     movl    EXP_UNDER+1,%ecx
  468.     subl    EXP(%edi),%ecx
  469.  
  470.     cmpl    $64,%ecx    /* shrd only works for 0..31 bits */
  471.     jnc    xDenorm_shift_more_than_63
  472.  
  473.     cmpl    $32,%ecx    /* shrd only works for 0..31 bits */
  474.     jnc    xDenorm_shift_more_than_32
  475.  
  476. /*
  477.  * We got here without jumps by assuming that the most common requirement
  478.  *   is for a small de-normalising shift.
  479.  * Shift by [1..31] bits
  480.  */
  481.     addl    %ecx,EXP(%edi)
  482.     orl    %edx,%edx    /* extension */
  483.     setne    %ch        /* Save whether %edx is non-zero */
  484.     xorl    %edx,%edx
  485.     shrd    %cl,%ebx,%edx
  486.     shrd    %cl,%eax,%ebx
  487.     shr    %cl,%eax
  488.     orb    %ch,%dl
  489.     popl    %ecx
  490.     jmp    xDenorm_done
  491.  
  492. /* Shift by [32..63] bits */
  493. xDenorm_shift_more_than_32:
  494.     addl    %ecx,EXP(%edi)
  495.     subb    $32,%cl
  496.     orl    %edx,%edx
  497.     setne    %ch
  498.     orb    %ch,%bl
  499.     xorl    %edx,%edx
  500.     shrd    %cl,%ebx,%edx
  501.     shrd    %cl,%eax,%ebx
  502.     shr    %cl,%eax
  503.     orl    %edx,%edx        /* test these 32 bits */
  504.     setne    %cl
  505.     orb    %ch,%bl
  506.     orb    %cl,%bl
  507.     movl    %ebx,%edx
  508.     movl    %eax,%ebx
  509.     xorl    %eax,%eax
  510.     popl    %ecx
  511.     jmp    xDenorm_done
  512.  
  513. /* Shift by [64..) bits */
  514. xDenorm_shift_more_than_63:
  515.     cmpl    $64,%ecx
  516.     jne    xDenorm_shift_more_than_64
  517.  
  518. /* Exactly 64 bit shift */
  519.     addl    %ecx,EXP(%edi)
  520.     xorl    %ecx,%ecx
  521.     orl    %edx,%edx
  522.     setne    %cl
  523.     orl    %ebx,%ebx
  524.     setne    %ch
  525.     orb    %ch,%cl
  526.     orb    %cl,%al
  527.     movl    %eax,%edx
  528.     xorl    %eax,%eax
  529.     xorl    %ebx,%ebx
  530.     popl    %ecx
  531.     jmp    xDenorm_done
  532.  
  533. xDenorm_shift_more_than_64:
  534.     movl    EXP_UNDER+1,EXP(%edi)
  535. /* This is easy, %eax must be non-zero, so.. */
  536.     movl    $1,%edx
  537.     xorl    %eax,%eax
  538.     xorl    %ebx,%ebx
  539.     popl    %ecx
  540.     jmp    xDenorm_done
  541.  
  542.  
  543. xUnmasked_underflow:
  544.     movb    UNMASKED_UNDERFLOW,FPU_denormal
  545.     jmp    xDenorm_done
  546.  
  547.  
  548. /* Undo the de-normalisation. */
  549. xNormalise_result:
  550.     cmpb    UNMASKED_UNDERFLOW,FPU_denormal
  551.     je    xSignal_underflow
  552.  
  553. /* The number must be a denormal if we got here. */
  554. #ifdef PARANOID
  555.     /* But check it... just in case. */
  556.     cmpl    EXP_UNDER+1,EXP(%edi)
  557.     jne    L_norm_bugged
  558. #endif PARANOID
  559.  
  560. #ifdef PECULIAR_486
  561.     /*
  562.      * This implements a special feature of 80486 behaviour.
  563.      * Underflow will be signalled even if the number is
  564.      * not a denormal after rounding.
  565.      * This difference occurs only for masked underflow, and not
  566.      * in the unmasked case.
  567.      * Actual 80486 behaviour differs from this in some circumstances.
  568.      */
  569.     orl    %eax,%eax        /* ms bits */
  570.     js    LNormalise_shift_done    /* Will be masked underflow */
  571. #endif PECULIAR_486
  572.  
  573.     orl    %eax,%eax        /* ms bits */
  574.     js    xL_Normalised        /* No longer a denormal */
  575.  
  576.     jnz    LNormalise_shift_up_to_31    /* Shift left 0 - 31 bits */
  577.  
  578.     orl    %ebx,%ebx
  579.     jz    L_underflow_to_zero    /* The contents are zero */
  580.  
  581. /* Shift left 32 - 63 bits */
  582.     movl    %ebx,%eax
  583.     xorl    %ebx,%ebx
  584.     subl    $32,EXP(%edi)
  585.  
  586. LNormalise_shift_up_to_31:
  587.     bsrl    %eax,%ecx    /* get the required shift in %ecx */
  588.     subl    $31,%ecx
  589.     negl    %ecx
  590.     shld    %cl,%ebx,%eax
  591.     shl    %cl,%ebx
  592.     subl    %ecx,EXP(%edi)
  593.  
  594. LNormalise_shift_done:
  595.     testb    $0xff,FPU_bits_lost    /* bits lost == underflow */
  596.     jz    xL_Normalised
  597.  
  598.     /* There must be a masked underflow */
  599.     push    %eax
  600.     pushl    EX_Underflow
  601.     call    _exception
  602.     popl    %eax
  603.     popl    %eax
  604.     jmp    xL_Normalised
  605.  
  606.  
  607. /*
  608.  * The operations resulted in a number too small to represent.
  609.  * Masked response.
  610.  */
  611. L_underflow_to_zero:
  612.     push    %eax
  613.     call    _set_precision_flag_down
  614.     popl    %eax
  615.  
  616.     push    %eax
  617.     pushl    EX_Underflow
  618.     call    _exception
  619.     popl    %eax
  620.     popl    %eax
  621.  
  622. /* Reduce the exponent to EXP_UNDER */
  623.     movl    EXP_UNDER,EXP(%edi)
  624.     movb    TW_Zero,TAG(%edi)
  625.     jmp    xL_Store_significand
  626.  
  627.  
  628. /* The operations resulted in a number too large to represent. */
  629. L_overflow:
  630.     push    %edi
  631.     call    _arith_overflow
  632.     pop    %edi
  633.     jmp    fpu_reg_round_exit
  634.  
  635.  
  636. xSignal_underflow:
  637.     /* The number may have been changed to a non-denormal */
  638.     /* by the rounding operations. */
  639.     cmpl    EXP_UNDER,EXP(%edi)
  640.     jle    xDo_unmasked_underflow
  641.  
  642.     jmp    xL_Normalised
  643.  
  644. xDo_unmasked_underflow:
  645.     /* Increase the exponent by the magic number */
  646.     addl    $(3*(1<<13)),EXP(%edi)
  647.     push    %eax
  648.     pushl    EX_Underflow
  649.     call    EXCEPTION
  650.     popl    %eax
  651.     popl    %eax
  652.     jmp    xL_Normalised
  653.  
  654.  
  655. #ifdef PARANOID
  656. #ifdef PECULIAR_486
  657. L_bugged_denorm_486:
  658.     pushl    EX_INTERNAL|0x236
  659.     call    EXCEPTION
  660.     popl    %ebx
  661.     jmp    L_exception_exit
  662. #else
  663. L_bugged_denorm:
  664.     pushl    EX_INTERNAL|0x230
  665.     call    EXCEPTION
  666.     popl    %ebx
  667.     jmp    L_exception_exit
  668. #endif PECULIAR_486
  669.  
  670. L_bugged_round24:
  671.     pushl    EX_INTERNAL|0x231
  672.     call    EXCEPTION
  673.     popl    %ebx
  674.     jmp    L_exception_exit
  675.  
  676. L_bugged_round53:
  677.     pushl    EX_INTERNAL|0x232
  678.     call    EXCEPTION
  679.     popl    %ebx
  680.     jmp    L_exception_exit
  681.  
  682. L_bugged_round64:
  683.     pushl    EX_INTERNAL|0x233
  684.     call    EXCEPTION
  685.     popl    %ebx
  686.     jmp    L_exception_exit
  687.  
  688. L_norm_bugged:
  689.     pushl    EX_INTERNAL|0x234
  690.     call    EXCEPTION
  691.     popl    %ebx
  692.     jmp    L_exception_exit
  693.  
  694. L_entry_bugged:
  695.     pushl    EX_INTERNAL|0x235
  696.     call    EXCEPTION
  697.     popl    %ebx
  698. L_exception_exit:
  699.     mov    $1,%eax
  700.     jmp    fpu_reg_round_exit
  701. #endif PARANOID
  702.